using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using LunarWorldSDK.Security;
using System.Xml.Serialization;
using LitJson;

/// <summary>
/// Contains helper classes for serialization/deserialization with encryption features
/// </summary>
namespace LunarWorldSDK.Serialization
{
    #region Binary
    /// <summary>
    /// Helper class for Binary Serialization
    /// </summary>
    public static class SerializerBinary
    {
        public static void Serialize(object obj, string FilePath, bool IsEncrypted = false)
        {
            BinaryFormatter bn = new BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            bn.Serialize(mem, obj);
            byte[] plaindata = mem.ToArray();
            mem.Dispose();
            mem.Close();
            byte[] dataencrypted = (IsEncrypted) ? EncryptionUtility.EncryptByteArray(plaindata) :
                plaindata;
            if (File.Exists(FilePath)) File.Delete(FilePath);
            FileStream file = new FileStream(FilePath, FileMode.Create);
            bn.Serialize(file, dataencrypted);
            file.Close();
        }

        public static T Deserialize<T>(string FilePath, bool IsEncrypted = false)
        {
            if (File.Exists(FilePath))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                FileStream file = new FileStream(FilePath, FileMode.Open);
                byte[] encrypted = (byte[])formatter.Deserialize(file);
                file.Close();
                byte[] desencrypted = (IsEncrypted) ? EncryptionUtility.DecryptByteArray(encrypted) :
                    encrypted;
                MemoryStream DeserializationStream = new MemoryStream(desencrypted);
                T data = (T)formatter.Deserialize(DeserializationStream);
                DeserializationStream.Dispose();
                DeserializationStream.Close();
                return data;
            }
            else
            {
                return default(T);
            }
        }
    }
    #endregion

    #region Json

    /// <summary>
    /// Helper class for Json Serialization
    /// this method can serialize to many of unity data types.
    /// </summary>
    public static class SerializerJson
    {
        public static string SerializeToJson(object obj, bool IsEncrypted = false )
        {
            if (IsEncrypted)
                return EncryptionUtility.EncryptString(JsonMapper.ToJson(obj));
            else
                return JsonMapper.ToJson(obj);
        }

        public static T DeserializeFromJson<T>(string Json, bool IsEncrypted = false)
        {
            if (IsEncrypted)
                return JsonMapper.ToObject<T>(EncryptionUtility.DecryptString(Json));
            else
                return JsonMapper.ToObject<T>(Json);
        }

        public static void SerializeToFile(object obj, string FilePath , bool IsEncrypted = false)
        {
            if (File.Exists(FilePath)) File.Delete(FilePath);
            string _text = SerializeToJson(obj , IsEncrypted);
            File.WriteAllText(FilePath, _text);
        }

        public static T DeserializeFromFile<T>(string Filepath, bool IsEncrypted = false )
        {
            if (File.Exists(Filepath))
            {
                string _json = File.ReadAllText(Filepath);
                return DeserializeFromJson<T>(_json , IsEncrypted);
            }
            else
            {
                return default(T);
            }
        }
    }
    #endregion

    #region Xml

    /// <summary>
    /// Helper class for Xml Serialization
    /// </summary>
    public static class SerializerXml
    {

        public static void SerializeXML( object obj , string FilePath, bool IsEncrypted = false)
        {
            XmlSerializer ser = new XmlSerializer(obj.GetType());
            if (File.Exists(FilePath)) File.Delete(FilePath);

            MemoryStream mem = new MemoryStream();

            ser.Serialize(mem, obj);

            string txt = EncryptionUtility.ByteArrayToString(mem.ToArray());

            mem.Dispose();
            mem.Close();

            string finaltext = (IsEncrypted) ? EncryptionUtility.EncryptString(txt) : txt;

            byte[] data = EncryptionUtility.StringToByeArray(finaltext);

            mem = new MemoryStream(data);

            FileStream file = new FileStream(FilePath, FileMode.Create);

            mem.WriteTo(file);

            file.Close();
            mem.Dispose();
            mem.Close();
        }

        public static T DeserializeXML<T>(string FilePath, bool IsEncrypted = false)
        {
            if (File.Exists(FilePath))
            {

                byte[] Loadedbytes = File.ReadAllBytes(FilePath);

                string txt = (IsEncrypted) ? EncryptionUtility.DecryptString(EncryptionUtility.ByteArrayToString(Loadedbytes)) :
                    EncryptionUtility.ByteArrayToString(Loadedbytes);

                byte[] FinalBytes = EncryptionUtility.StringToByeArray(txt);

                XmlSerializer ser = new XmlSerializer(typeof(T));

                MemoryStream mem = new MemoryStream(FinalBytes);

                T data = (T)ser.Deserialize(mem);
                mem.Dispose();
                mem.Close();
                return data;
            }
            else
            {
                return default(T);
            }
        }

    }
    #endregion
}